package com.panghl.listener;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * @Author panghl
 * @Date 2021/6/19 11:08
 * ApplicationContext 是 Spring 的核心接口或容器。它的功能很多，通过它，我们可以创建、获取、管理 bean；可以发布事件；可以载资源文件；可以获取容器当前运行的环境。Spring 为了更灵活的配置 ApplicationContext，在容器初始化的过程中，Spring 允许用户修改这个对象，具体的方法就是扩展 ApplicationContextInitializer。
 *
 * 总结
 * 1.ApplicationContextInitializer 是 Spring 对外提供的扩展点之一，用于在 ApplicationContext 容器加载 Bean 之前对当前的上下文进行配置。
 * 2.ApplicationContextInitializer 的实现有三种，第一种是在 classpath 路径下的 META-INF/spring.factories 文件中填写接口和实现类的全名，多个实现的话用逗号分隔。第二种是在 Spring Boot 启动代码中手动添加初始化器，第三种是在 application.properties 中配置 context.initializer.classes。
 * 3.SpringFactoriesLoader 是 spring 提供的，用于加载外部项目配置的加载器。他会固定的读取 META-INF/spring.factories 文件，解析该文件，获得指定接口的实现类。SpringFactoriesLoader 这种加载配置的方式是典型的 SPI 方式，在 Spring Boot 中大量使用，这种方式将服务接口与服务实现分离，达到解耦、提高可扩展性的目的。
 * 4.Spring Boot 内置了一些初始化器，大部分功能是配置环境变量，比如 ServerPortInfoApplicationContextInitializer，实现手段是为 ApplicationContext 增加监听器。还用于配置日志，比如 ConfigurationWarningsApplicationContextInitializer 实现手段是增加 Bean 后处理器做校验。比较特殊的是 DelegatingApplicationContextInitializer，它会获得 application.properties 中配置的 context.initializer.classes，将其作为初始化器进行加载和执行。
 **/
public class MyApplicationContextInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 打印容器里面有多少个bean
        System.out.println("bean count=====" + applicationContext.getBeanDefinitionCount());
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println("environment.getSystemEnvironment-->"+environment.getSystemEnvironment());
        System.out.println("environment.getSystemProperties-->"+environment.getSystemProperties());
        // 打印出所有 beanName
        System.out.println(applicationContext.getBeanDefinitionCount() + "个Bean的名字如下：");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames) {
            System.out.println(beanName);
        }
        System.out.println("MyApplicationContextInitializer 。。。。 initialize");
    }

}
